package com.yunhe.authority.repository.authority;

import com.yunhe.authority.domain.authority.Role;
import com.yunhe.authority.domain.authority.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 角色Repository
 * @author liuronglei
 */
@Repository
public interface RoleRepository extends Neo4jRepository<Role, Long> {

    @Query("match(r:Role)-[:HAS_CHILD*0..9]->(s:Role) where ID(r)={id} set r.activity=false,s.activity=false")
    void deleteRole(@Param("id") Long id);

    @Query("match(user)-[:HAS_ROLE]->(roles) where ID(user)={userId} return roles")
    List<Role> findRolesByUserId(@Param("userId") Long userId);

    Role findByName(String name);

    @Query("match p=(r{activity:true})-[:HAS_CHILD*0..1]->(s{activity:true}) where ID(r)={id} return p")
    Iterable<Role> findRolesById(@Param("id") Long id);

    @Query("match p=(r)-[:HAS_CHILD*0..9]->(s) where ID(r)={id} return p")
    Iterable<Role> findRolesByRootId(@Param("id") Long id);

    Iterable<Role> findByNameLikeOrTitleLike(String name, String title);

    Iterable<Role> findByNameLikeOrTitleLike(String name, String title, Sort sort);

    Page<Role> findByNameLikeOrTitleLike(String name, String title, Pageable pageable);

    Page<Role> findByTitleLike(String title, Pageable pageable);

    Iterable<Role> findByTitleContaining(String title);

    @Query("start role=node({roleId}),menu=node({menuId}) create (role)-[:HAS_MENU]->(menu)")
    void bindMenu(@Param("roleId") Long roleId, @Param("menuId") Long menuId);

    @Query("start role=node({roleId}),menu=node({menuId}) create (role)-[:HAS_OPTIONAL_MENU]->(menu)")
    void bindHasMenu(@Param("roleId") Long roleId, @Param("menuId") Long menuId);

    @Query("start role=node({roleId}),menu=node({menuId}) create (role)-[:HAS_MENU_APP]->(menu)")
    void bindAppMenu(@Param("roleId") Long roleId, @Param("menuId") Long menuId);

    @Query("start role=node({roleId}),menu=node({menuId}) create (role)-[:HAS_OPTIONAL_MENU_APP]->(menu)")
    void bindHasAppMenu(@Param("roleId") Long roleId, @Param("menuId") Long menuId);

    @Query("start role=node({roleId}),menu=node({menuId}) match(role)-[r:HAS_MENU]->(menu) delete r")
    void unbindMenu(@Param("roleId") Long roleId, @Param("menuId") Long menuId);

    @Query("start role=node({roleId}),menu=node({menuId}) match(role)-[r:HAS_MENU_APP]->(menu) delete r")
    void unbindAppMenu(@Param("roleId") Long roleId, @Param("menuId") Long menuId);

    @Query("start role=node({roleId}),menu=node({menuId}) match(role)-[r:HAS_OPTIONAL_MENU]->(menu) delete r")
    void unbindHasMenu(@Param("roleId") Long roleId, @Param("menuId") Long menuId);

    @Query("start role=node({roleId}),menu=node({menuId}) match(role)-[r:HAS_OPTIONAL_MENU_APP]->(menu) delete r")
    void unbindHasAppMenu(@Param("roleId") Long roleId, @Param("menuId") Long menuId);

    @Query("start role=node({roleId}) match(role)-[r:HAS_MENU]->()   delete r")
    void unbindAllMenus(@Param("roleId") Long roleId);

    @Query("start role=node({roleId}) match(role)-[r:HAS_OPTIONAL_MENU]->() delete r")
    void unbindAllHasMenus(@Param("roleId") Long roleId);

    @Query("start role=node({roleId}) match(role)-[r:HAS_MENU_APP]->() delete r")
    void unbindAllAppMenus(@Param("roleId") Long roleId);

    @Query("start role=node({roleId}) match(role)-[r:HAS_OPTIONAL_MENU_APP]->() delete r")
    void unbindAllHasAppMenus(@Param("roleId") Long roleId);

    @Query("match(u:User)-[:HAS_ROLE]->(r:Role) where ID(r)={id} return u")
    Iterable<User> findUsersById(@Param("id") Long id);

    @Query("match(u:User)-[:HAS_ROLE]->(r:Role) where ID(r)={id} return count(u)")
    Long findUsersNumberById(@Param("id") Long id);

    @Query("match(parent)-[r:HAS_CHILD]->(role) where ID(role)={id} delete r")
    void unbindParentRoleById(@Param("id") Long id);

    @Query("start n=node({parentId}),m=node({childId}) create (n)-[:HAS_CHILD]->(m)")
    void bindChildRoleById(@Param("parentId") Long parentId, @Param("childId") Long childId);

    @Query("match(r:Role) match(s:Station) where ID(r)={roleId} and ID(s)={stationId} create (r)-[:HAS_STATION]->(s)")
    void bindStation(@Param("roleId") Long roleId, @Param("stationId") Long stationId);

    @Query("match(r:Role) match(s:Station) where ID(r)={roleId} and ID(s)={stationId} " +
            "create (r)-[:HAS_OPTIONAL_STATION]->(s)")
    void bindHasStation(@Param("roleId") Long roleId, @Param("stationId") Long stationId);

    @Query("start role=node({roleId}),station=node({stationId}) match(role)-[r:HAS_STATION]->(station) delete r")
    void unbindStation(@Param("roleId") Long roleId, @Param("menuId") Long menuId);

    @Query("start role=node({roleId}),station=node({stationId}) match(role)-[r:HAS_OPTIONAL_STATION]->(station) delete r")
    void unbindHasStation(@Param("roleId") Long roleId, @Param("menuId") Long menuId);

    @Query("start role=node({roleId}) match(role)-[r:HAS_STATION]->() delete r")
    void unbindAllStations(@Param("roleId") Long roleId);

    @Query("start role=node({roleId}) match(role)-[r:HAS_OPTIONAL_STATION]->() delete r")
    void unbindAllHasStations(@Param("roleId") Long roleId);

    @Query("match(r:Role)<-[:HAS_CHILD]-(p:Role) where ID(r)={id} return p")
    Role getParentRole(@Param("id") Long id);

    @Query("match(r:Role) where r.level=0 return r limit 1")
    Role findRootRole();

    @Query("match(u2:User{activity:true})-[:HAS_ROLE]->(r:Role)-[:HAS_CHILD*0..9]->(s)<-[:HAS_ROLE]-(u1:User{activity:true}) where ID(r)={id} return u1,u2")
    Iterable<User> findAllUsersById(@Param("id") Long id);

    @Query("match(u:User{activity:true})-[:HAS_ROLE]->(r:Role) where ID(r)={id} return u")
    Iterable<User> findActiveUsersById(@Param("id") Long id);

    @Query("match(u:User)-[:HAS_ROLE]->(r:Role) where ID(r)={id} return u")
    Iterable<User> findBindUsersById(@Param("id") Long id);

    @Query("match(r:Role) where r.title={title} return r limit 1")
    Role findByTitle(@Param("title") String title);

    @Query("start n=node({id1}),m=node({id2}) return exists((n)-[:HAS_CHILD*0..2]->(m)")
    Boolean findExists(@Param("id1") Long id1, @Param("id2") Long id2);

    /****************************20210226*********************************/

    /**
     * 默认单位绑定角色
     * 这边f.id与id(f)不一样，因为一些问题所以这么写
     * @param roleId 角色id
     * @param firmId 单位id
     */
    @Query("match(r:Role) match(f:Firm) where ID(r)={roleId} and f.id={firmId} create (f)-[:HAS_ROLE]->(r)")
    void bindDefaultFirm(@Param("roleId") Long roleId, @Param("firmId") Long firmId);

    /**
     * 单位绑定角色
     * @param roleId 角色id
     * @param firmId 单位id
     */
    @Query("match(r:Role) match(f:Firm) where ID(r)={roleId} and ID(f)={firmId} create (f)-[:HAS_ROLE]->(r)")
    void bindFirm(@Param("roleId") Long roleId, @Param("firmId") Long firmId);

    /**
     * 项目绑定角色
     * @param roleId 角色id
     * @param stationId 项目id
     */
    @Query("match(r:Role) match(s:Station) where ID(r)={roleId} and ID(s)={stationId} create (s)-[:HAS_ROLE]->(r)")
    void roleBindStation(@Param("roleId") Long roleId, @Param("stationId") Long stationId);

    /**
     * 根据项目id查询角色列表
     * @param stationId 项目id
     * @return
     */
    @Query("match(s:Station)-[:HAS_ROLE]->(r:Role) where ID(s)={stationId} return r")
    Iterable<Role> findRolesByStationId(@Param("stationId") Long stationId);

    /**
     * 根据项目id和角色title查询角色列表
     * @param stationId 项目id
     * @param title 角色title
     * @return
     */
    @Query("match(s:Station)-[:HAS_ROLE]->(r:Role) where ID(s)={stationId} and r.title={title} return r limit 1")
    Role findRoleByStationIdAndTitle(@Param("stationId") Long stationId, @Param("title") String title);

    /**
     * 根据默认单位id查询角色列表
     * @param firmId 单位id
     * 这边f.id与id(f)不一样，因为一些问题所以这么写
     * @return Iterable
     */
    @Query("match(f:Firm)-[:HAS_ROLE]->(r:Role) where f.id={firmId} return r")
    Iterable<Role> findRolesByDefaultFirmId(@Param("firmId") Long firmId);

    /**
     * 根据默认单位id和角色title查询角色
     * @param firmId 单位id
     * @param title 角色title
     * 这边f.id与id(f)不一样，因为一些问题所以这么写
     * @return Role
     */
    @Query("match(f:Firm)-[:HAS_ROLE]->(r:Role) where f.id={firmId} and r.title={title} return r limit 1")
    Role findRolesByDefaultFirmIdAndTitle(@Param("firmId") Long firmId, @Param("title") String title);

    /**
     * 根据单位id查询角色列表
     * @param firmId 单位id
     * @return
     */
    @Query("match(f:Firm)-[:HAS_ROLE]->(r:Role) where ID(f)={firmId} return r")
    Iterable<Role> findRolesByFirmId(@Param("firmId") Long firmId);

    /**
     * 根据项目id和角色title查询角色列表
     * @param stationId 项目id
     * @param title 角色title
     * @return
     */
    @Query("match(f:Firm)-[:HAS_ROLE]->(r:Role) where ID(f)={firmId} and r.title={title} return r limit 1")
    Role findRoleByFirmIdAndTitle(@Param("stationId") Long stationId, @Param("title") String title);

    /**
     * 通过角色id 批量查询角色信息
     * @param roleIds
     * @return
     */
    @Query("match(r:Role) where ID(r) IN {roleIds} return r ")
    Iterable<Role> findByIds(@Param("roleIds") List<Long> roleIds);

    /**
     * 查询用户和项目的角色
     * @param userId
     * @param stationId
     * @return
     */
    @Query("MATCH(r:Role)<-[:HAS_ROLE{stationId:{stationId}}]-(u:User) where ID(u)={userId} return r")
    Iterable<Role> findByUserIdAndStationId(@Param("userId") Long userId,@Param("stationId") Long stationId);

    /**
     * 查询用户和单位的角色
     * @param userId
     * @param firmId
     * @return
     */
    @Query("MATCH(u:User)-[:HAS_ROLE{firmId:{firmId}}]->(r:Role) where ID(u)={userId} return r")
    Iterable<Role> findByUserIdAndFirmId(@Param("userId") Long userId,@Param("firmId")  Long firmId);

    @Query("MATCH(u:User)-[:HAS_ROLE{stationId:{stationId}}]->(r:Role) where ID(u)={userId} AND r.title=~{roleTitle} return r")
    Iterable<Role> findByUserIdAndStationId(@Param("userId") Long userId,@Param("stationId") Long stationId,@Param("roleTitle") String roleTitle);

    @Query("MATCH(u:User)-[:HAS_ROLE{firmId:{firmId}}]->(r:Role) where ID(u)={userId} AND r.title=~{roleTitle} return r")
    Iterable<Role> findByUserIdAndFirmId(@Param("userId") Long userId,@Param("firmId")  Long firmId,@Param("roleTitle") String roleTitle);


    /********************企业********************/

    /**
     * 企业绑定角色
     * @param roleId 角色id
     * @param companyId 企业id
     */
    @Query("match(r:Role) match(c:Company) where ID(r)={roleId} and ID(c)={companyId} create (c)-[:HAS_ROLE]->(r)")
    void bindCompany(@Param("roleId") Long roleId, @Param("companyId") Long companyId);

    /**
     * 根据企业id和角色title查询角色列表
     * @param companyId 企业id
     * @param title 角色title
     * @return Role
     */
    @Query("match(c:Company)-[:HAS_ROLE]->(r:Role) where ID(c)={companyId} and r.title={title} return r limit 1")
    Role findRoleByCompanyIdAndTitle(@Param("companyId") Long companyId, @Param("title") String title);

    /**
     * 根据企业id和角色title查询角色列表
     * @param companyId 企业id
     * @return Role
     */
    @Query("match(c:Company)-[:HAS_ROLE]->(r:Role) where ID(c)={companyId} return r")
    Iterable<Role> findRoleByCompanyId(@Param("companyId") Long companyId);

    @Query("start role=node({roleId}) match(role)-[r:HAS_MENU]->(m:Menu) where m.systemMenuCategory={systemMenuCategory} delete r")
    void unbindAllMenusAndSystemMenuCategory(@Param("roleId") Long roleId,@Param("systemMenuCategory")  String systemMenuCategory);

    /**
     * 根据企业员工id获取绑定的角色列表
     * @param employeeId 企业员工id
     * @return Iterable<Role>
     */
    @Query("MATCH(e:Employee)-[:HAS_ROLE]->(r:Role) where ID(e)={employeeId} return r")
    Iterable<Role> findRoleByEmployeeId(@Param("employeeId") Long employeeId);
}